﻿__author__ = 'Pawel Kowalski'
#
# This script was created to demonstrate the use of Python in Autodesk 3D Studio Max
#
# Copyright (C) Pawel Kowalski
# www.pkowalski.com
# www.behance.net/pkowalski
#
# Open the script from 3D Studio Max Listener with command:
# python.ExecuteFile "path`to`file\main.py"
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
#
# To run the script execute:
# python.ExecuteFile "path:\to\Script_3DSMax.py"
# in MAXScript Listener
#
#
#


import time  # To measure execution times
import random
import math
import os.path
import ctypes

try:
    # Max2016 - PySide & Qt4
    from PySide.QtCore import Qt, SIGNAL
    from PySide.QtGui import (QMessageBox, QListWidgetItem, QFileDialog, QDialog, QWidget, QGridLayout, QLabel,
                              QPushButton, QListWidget, QDesktopWidget)
    from shiboken import wrapInstance
except ImportError:
    # Max2017+ - PySide2 & Qt5
    from PySide2.QtCore import Qt, SIGNAL
    from shiboken2 import wrapInstance
    from PySide2.QtWidgets import (QMessageBox, QListWidgetItem, QFileDialog, QDialog, QWidget, QGridLayout, QLabel,
                                   QPushButton, QListWidget, QDesktopWidget)

import MaxPlus  # This module contains all the classes and functions of the 3ds Max Python API

FPS = MaxPlus.Core.EvalMAXScript('frameRate').GetInt()
TICKS = 4800 / FPS  # 3D Studio Max uses internal time unit: tick. there are 4800 ticks for second.


#
#
# Support functions for creating and animating scene:
#
#


def set_scale_keys(target, keyframes, multiply_by_ticks=True):
    """
    Function animates the scale of given object by creating the given keyframes.
    Animation is done with a use of AutoKey function of 3Ds Max.
    The AutoKey function can be set with:
    MaxPlus.Animation.SetAnimateButtonState(Bool)

    :param target:  MaxPlus.INode - Object which scale will be animated
    :param keyframes: Python list - Keyframes that will be created: [[int time, float scale (1 = 100%),] ...]
    :param multiply_by_ticks: Boolean - Set to False if time in list of keyframes is already multiplied by TICKS.
    """

    current_scale = 1.0  # Need to remember the history of scaling to convert absolute values of keyframes to relative
    is_first_frame = True
    MaxPlus.Animation.SetAnimateButtonState(True)  # Enable AutoKey
    MaxPlus.Animation.SetDefaultTangentType(3, 3)  # Set tangent to fast - just for the first frame
    for keyframe in keyframes:  # For every keyframe from the list of keyframes scale object at proper time
        scale_value = float(keyframe[0])
        scale = MaxPlus.Point3(scale_value / current_scale, scale_value / current_scale, scale_value / current_scale)

        if multiply_by_ticks:  # If the time value in keyframes was not converted to ticks, it will be now
            target.Scale(scale, int(keyframe[1] * TICKS))
        else:
            target.Scale(scale, int(keyframe[1]))
        current_scale = scale_value

        if is_first_frame:  # 3Ds Max creates a keyframe in 0 with current value by default.
            is_first_frame = False  # It need to be overrided, if the frame of key that is being created is not 0.
            MaxPlus.Animation.SetDefaultTangentType(5, 5)
            if int(keyframe[1]) != 0:
                target.Scale(scale, 0)

    MaxPlus.Animation.SetAnimateButtonState(False)


def leafs_rotations(number_of_leafs):
    """
    Creates the list of angles of leafs around the palm tree.
    Leafs should be placed more or less evenly around the trunk but appear to be placed randomly.
    The leafs should not be placed too close, because they would overlap.

    :param number_of_leafs: int - Number of leafs
    :return: Python list - List of angles of leafs around the palm tree
    """

    x = -math.pi  # Leafs are placed around the trunk, so the range is 2*pi (360 deg). x = 0, y = 2*pi would also be ok.
    y = math.pi
    angles = []
    jump = (y - x) / float(number_of_leafs)  # Divide the range by the number of leafs and create an array

    while x < y:
        random.seed()  #
        angles.append(random.uniform(x - (jump / 3.0), x + (jump / 3.0)))  # every leaf is placed +/- (1/3)*interval
        x += jump

    return angles


def set_position_keys(target, keyframes):
    """
    Function animates the position of given object by creating the given keyframes.
    Animation is done with a use of AutoKey function of 3Ds Max.
    The AutoKey function can be set with:
    MaxPlus.Animation.SetAnimateButtonState(Bool)

    :param target:  MaxPlus.INode - Object which scale will be animated
    :param keyframes: Python list - Keyframes that will be created: [[int time, [float x, float y, float z]], ...]
    """

    is_first_frame = True
    MaxPlus.Animation.SetAnimateButtonState(True)

    for keyframe in keyframes:
        MaxPlus.Animation.SetTime(keyframe[1] * TICKS)
        MaxPlus.Animation.SetDefaultTangentType(keyframe[2][0], keyframe[2][1])
        target.Position = MaxPlus.Point3(keyframe[0][0], keyframe[0][1], keyframe[0][2])

        if is_first_frame:  # 3Ds Max creates a keyframe in 0 with current value by default.
            is_first_frame = False  # It need to be overrided, if the frame of key that is being created is not 0.
            if int(keyframe[1]) != 0:
                target.Position = MaxPlus.Point3(keyframe[0][0], keyframe[0][1], keyframe[0][2])

    MaxPlus.Animation.SetAnimateButtonState(False)


def make_shark_mesh(mesh):
    """
    Creates a simple mesh of shark fin.
    Function is written in a readable and easy to interpret, but not effective way.
    The mesh is created based on saved positions of verticles and parameters of faces.
    Data has been generated from object modeled in 3Ds Max with a use of obj_to_code.ms script.
    Similar functions can be used in importer plugin.

    :param mesh: MaxPlus.Mesh - The mesh that will be modified
    """

    mesh.SetNumVerts(12)  # Firstly, the number of faces and vertices has to be set.
    mesh.SetNumFaces(20)

    mesh.SetVert(0, MaxPlus.Point3(-2.42281, -0.814631, 1.55561))  # Position of vertex.
    mesh.SetVert(1, MaxPlus.Point3(0.0166863, -0.854455, 1.91858))
    mesh.SetVert(2, MaxPlus.Point3(-2.42281, -0.482041, 1.55561))
    mesh.SetVert(3, MaxPlus.Point3(0.0166863, -0.44221, 1.91858))
    mesh.SetVert(4, MaxPlus.Point3(-2.57592, -0.814631, 3.45857))
    mesh.SetVert(5, MaxPlus.Point3(-1.41455, -0.810425, 3.54678))
    mesh.SetVert(6, MaxPlus.Point3(-2.57592, -0.482041, 3.45857))
    mesh.SetVert(7, MaxPlus.Point3(-1.41455, -0.486246, 3.54678))
    mesh.SetVert(8, MaxPlus.Point3(-2.54367, -0.8214, -0.819357))
    mesh.SetVert(9, MaxPlus.Point3(-2.54367, -0.475272, -0.819357))
    mesh.SetVert(10, MaxPlus.Point3(0.422536, -0.421143, -0.277747))
    mesh.SetVert(11, MaxPlus.Point3(0.422536, -0.875526, -0.277747))

    mesh.GetFace(0).SetVerts(8, 10, 11)  # Vertices of face.
    mesh.GetFace(0).SetEdgeVisFlags(1, 1, 0)
    mesh.GetFace(1).SetVerts(4, 7, 6)
    mesh.GetFace(1).SetEdgeVisFlags(1, 1, 0)
    mesh.GetFace(2).SetVerts(0, 5, 4)
    mesh.GetFace(2).SetEdgeVisFlags(1, 1, 0)
    mesh.GetFace(3).SetVerts(1, 7, 5)
    mesh.GetFace(3).SetEdgeVisFlags(1, 1, 0)
    mesh.GetFace(4).SetVerts(3, 6, 7)
    mesh.GetFace(4).SetEdgeVisFlags(1, 1, 0)
    mesh.GetFace(5).SetVerts(2, 4, 6)
    mesh.GetFace(5).SetEdgeVisFlags(1, 1, 0)
    mesh.GetFace(6).SetVerts(0, 9, 8)
    mesh.GetFace(6).SetEdgeVisFlags(1, 1, 0)
    mesh.GetFace(7).SetVerts(2, 10, 9)
    mesh.GetFace(7).SetEdgeVisFlags(1, 1, 0)
    mesh.GetFace(8).SetVerts(3, 11, 10)
    mesh.GetFace(8).SetEdgeVisFlags(1, 1, 0)
    mesh.GetFace(9).SetVerts(1, 8, 11)
    mesh.GetFace(9).SetEdgeVisFlags(1, 1, 0)
    mesh.GetFace(10).SetVerts(8, 9, 10)
    mesh.GetFace(10).SetEdgeVisFlags(1, 1, 0)
    mesh.GetFace(11).SetVerts(4, 5, 7)
    mesh.GetFace(11).SetEdgeVisFlags(1, 1, 0)
    mesh.GetFace(12).SetVerts(0, 1, 5)
    mesh.GetFace(12).SetEdgeVisFlags(1, 1, 0)
    mesh.GetFace(13).SetVerts(1, 3, 7)
    mesh.GetFace(13).SetEdgeVisFlags(1, 1, 0)
    mesh.GetFace(14).SetVerts(3, 2, 6)
    mesh.GetFace(14).SetEdgeVisFlags(1, 1, 0)
    mesh.GetFace(15).SetVerts(2, 0, 4)
    mesh.GetFace(15).SetEdgeVisFlags(1, 1, 0)
    mesh.GetFace(16).SetVerts(0, 2, 9)
    mesh.GetFace(16).SetEdgeVisFlags(1, 1, 0)
    mesh.GetFace(17).SetVerts(2, 3, 10)
    mesh.GetFace(17).SetEdgeVisFlags(1, 1, 0)
    mesh.GetFace(18).SetVerts(3, 1, 11)
    mesh.GetFace(18).SetEdgeVisFlags(1, 1, 0)
    mesh.GetFace(19).SetVerts(1, 0, 8)
    mesh.GetFace(19).SetEdgeVisFlags(1, 1, 0)

    mesh.InvalidateGeomCache()  # Object gets displayed in the viewport
    mesh.InvalidateTopologyCache()


def make_cloud_mesh(mesh):
    """
    Creates a complex mesh of cloud.
    Function is written in an compact, more useful way.
    The mesh is created based on saved positions of verticles and parameters of faces.
    Data has been generated from object modeled in 3Ds Max with a use of obj_to_code_as_python_array.ms script.
    Similar functions can be used in importer plugin.

    :type mesh: MaxPlus.Mesh - Object which scale will be animated
    """

    verts_list = [[0, [-4.59048, -11.5324, -2.85738]], [1, [4.19166, -11.3976, -1.66769]],
                  [2, [-2.72098, 4.70308, -0.947684]], [3, [5.35751, 5.31851, -1.84713]],
                  [4, [-2.55545, -10.6202, 1.76613]], [5, [6.33762, -11.4932, 3.83193]],
                  [6, [-4.05797, 5.18567, 4.01239]], [7, [5.16506, 4.23825, 3.03181]],
                  [8, [-7.57451, -3.27952, -1.45211]], [9, [-5.04695, -3.47346, -2.50455]],
                  [10, [0.944433, 6.59175, -3.95915]], [11, [5.33078, -2.79647, -1.9336]],
                  [12, [-1.41402, -13.436, -1.63148]], [13, [2.25454, -13.8944, 4.36555]],
                  [14, [5.20539, -3.61147, 4.18473]], [15, [1.21982, 6.42224, 2.21349]],
                  [16, [-5.31748, -3.30419, 3.23747]], [17, [6.47434, -13.4315, 0.369284]],
                  [18, [-4.49047, -13.0672, -0.366047]], [19, [7.06894, 7.09671, -0.225245]],
                  [20, [-3.55781, 7.03288, 2.01675]], [21, [-4.64846, -11.0102, -2.8238]],
                  [22, [-5.21395, -10.2643, -2.81557]], [23, [-5.11732, -9.4053, -2.68607]],
                  [24, [-4.63491, -8.46356, -2.67066]], [25, [-4.67857, -7.34732, -3.28498]],
                  [26, [-4.66886, -6.0801, -2.95555]], [27, [-4.96425, -4.77316, -3.20924]],
                  [28, [-3.07051, 4.22094, -1.27774]], [29, [-3.28412, 3.47717, -1.22602]],
                  [30, [-3.06383, 2.42297, -1.70111]], [31, [-4.21875, 1.15586, -2.44524]],
                  [32, [-4.59185, 0.108139, -1.878]], [33, [-4.55174, -1.04221, -2.62517]],
                  [34, [-5.07763, -2.24332, -2.5385]], [35, [-2.5496, 5.2281, -1.08924]],
                  [36, [-2.47412, 5.97114, -1.56816]], [37, [-2.32934, 6.64407, -2.13384]],
                  [38, [-1.81588, 6.7158, -2.66064]], [39, [-1.09603, 6.51815, -3.1696]],
                  [40, [-0.384585, 6.59353, -3.55172]], [41, [0.2763, 6.63422, -3.91024]],
                  [42, [4.97608, 5.33017, -2.21633]], [43, [4.42463, 5.3988, -2.82698]],
                  [44, [3.87665, 5.59257, -3.30965]], [45, [3.39066, 6.12778, -3.09912]],
                  [46, [2.87637, 6.75938, -2.90991]], [47, [2.28094, 6.88389, -3.07711]],
                  [48, [1.62215, 6.6081, -3.54207]], [49, [5.6303, 4.88423, -1.69767]],
                  [50, [5.93795, 4.18237, -2.02055]], [51, [6.34299, 3.28777, -2.50259]],
                  [52, [6.01454, 2.16795, -2.41291]], [53, [5.48294, 0.915054, -1.48493]],
                  [54, [5.56809, -0.331761, -1.62049]], [55, [5.22757, -1.57047, -1.65198]],
                  [56, [4.34654, -10.8263, -1.71773]], [57, [4.03986, -10.0871, -1.25091]],
                  [58, [4.44435, -9.26752, -1.48684]], [59, [4.98975, -8.10985, -2.09718]],
                  [60, [5.97541, -6.66577, -2.29159]], [61, [6.40411, -5.31424, -1.4463]],
                  [62, [5.74385, -4.03539, -2.07227]], [63, [3.67823, -11.9509, -1.39023]],
                  [64, [2.99699, -12.6519, -1.24017]], [65, [2.34207, -12.9799, -1.36114]],
                  [66, [1.56308, -12.9821, -1.2517]], [67, [0.805849, -13.3548, -0.833223]],
                  [68, [0.0592078, -13.9428, -0.927655]], [69, [-0.69599, -13.9633, -1.40722]],
                  [70, [-4.48329, -11.8284, -3.03768]], [71, [-4.25605, -12.4004, -3.18883]],
                  [72, [-3.80349, -12.8516, -3.39871]], [73, [-3.33853, -12.9033, -3.36947]],
                  [74, [-2.8886, -12.6499, -2.84013]], [75, [-2.44545, -12.7983, -2.31099]],
                  [76, [-1.98028, -12.9664, -1.95086]], [77, [-2.35827, -11.0242, 1.95376]],
                  [78, [-2.04212, -11.8418, 2.40821]], [79, [-1.43451, -12.5864, 2.6025]],
                  [80, [-0.464936, -12.8909, 2.70888]], [81, [0.277662, -13.0811, 3.36934]],
                  [82, [0.744878, -13.5168, 3.99864]], [83, [1.39473, -13.9213, 4.33037]],
                  [84, [5.84659, -11.8736, 4.11287]], [85, [5.35056, -12.4986, 4.28095]],
                  [86, [4.93181, -13.3184, 4.37555]], [87, [4.62338, -14.1254, 4.68631]],
                  [88, [4.25795, -14.4315, 4.95028]], [89, [3.74167, -14.2483, 4.93854]],
                  [90, [3.06639, -13.9383, 4.62452]], [91, [6.93981, -10.9459, 3.54401]],
                  [92, [6.81082, -10.1381, 3.49907]], [93, [5.67307, -9.16372, 4.27475]],
                  [94, [5.07461, -8.06029, 4.44253]], [95, [5.59865, -6.89624, 3.44476]],
                  [96, [5.71477, -5.76001, 4.10377]], [97, [5.43378, -4.68175, 4.73674]],
                  [98, [5.26349, 3.76686, 2.83477]], [99, [5.03478, 3.10254, 2.51034]],
                  [100, [5.60882, 2.3842, 2.96899]], [101, [5.28509, 1.44248, 4.19756]],
                  [102, [5.06031, 0.227875, 4.11658]], [103, [5.74926, -1.10308, 4.13182]],
                  [104, [5.23316, -2.41592, 4.08796]], [105, [4.77104, 4.2432, 2.87455]],
                  [106, [4.26316, 4.37717, 2.64462]], [107, [3.77346, 4.88327, 2.60995]],
                  [108, [3.33051, 5.59131, 2.87838]], [109, [2.8952, 5.78294, 3.20531]],
                  [110, [2.40009, 5.74118, 3.04044]], [111, [1.83982, 6.00027, 2.49207]],
                  [112, [-3.6252, 5.55577, 4.01007]], [113, [-3.01992, 5.85201, 3.70423]],
                  [114, [-2.42564, 5.92598, 3.42756]], [115, [-1.77262, 6.08702, 3.08948]],
                  [116, [-1.00918, 6.32267, 2.76293]], [117, [-0.205574, 6.30027, 2.54408]],
                  [118, [0.543592, 6.39312, 2.26653]], [119, [-4.3646, 4.48682, 3.61868]],
                  [120, [-4.17321, 3.39143, 3.43435]], [121, [-4.33876, 2.23708, 3.90402]],
                  [122, [-4.28137, 1.23009, 3.54935]], [123, [-5.12764, 0.0918598, 3.99807]],
                  [124, [-5.19081, -1.02315, 3.43132]], [125, [-5.29362, -2.11191, 2.91219]],
                  [126, [-2.60726, -10.127, 2.17327]], [127, [-3.51078, -9.45301, 2.9977]],
                  [128, [-3.79006, -8.71694, 3.36178]], [129, [-4.10539, -7.95529, 2.76918]],
                  [130, [-4.42019, -6.85349, 2.78951]], [131, [-4.84402, -5.52935, 2.81615]],
                  [132, [-5.09285, -4.46128, 3.52657]], [133, [4.30574, -11.5671, -1.50565]],
                  [134, [4.50195, -11.8334, -1.25188]], [135, [4.83568, -12.1377, -0.98148]],
                  [136, [5.20644, -12.408, -0.722621]], [137, [5.55156, -12.5921, -0.461673]],
                  [138, [5.89193, -12.7367, -0.20753]], [139, [6.24181, -12.9731, 0.0607195]],
                  [140, [6.29933, -11.7357, 3.70063]], [141, [6.30325, -12.1743, 3.31666]],
                  [142, [6.22233, -12.6801, 2.81164]], [143, [5.95056, -13.1009, 2.2757]],
                  [144, [5.81332, -13.7173, 1.74536]], [145, [6.03473, -14.0856, 1.23336]],
                  [146, [6.39401, -13.9265, 0.764305]], [147, [-3.11063, -10.9355, 1.50183]],
                  [148, [-3.75236, -11.6171, 1.07977]], [149, [-4.00088, -12.4831, 0.713789]],
                  [150, [-3.78955, -13.2201, 0.516292]], [151, [-3.5181, -13.5544, 0.376321]],
                  [152, [-3.54252, -13.4297, 0.189794]], [153, [-3.90938, -13.1606, -0.068965]],
                  [154, [-4.75366, -11.8561, -2.68642]], [155, [-4.89771, -12.3524, -2.40486]],
                  [156, [-5.09703, -12.9067, -2.14409]], [157, [-5.40772, -13.3663, -1.91872]],
                  [158, [-5.6412, -13.5851, -1.59908]], [159, [-5.5659, -13.5145, -1.1818]],
                  [160, [-5.09332, -13.2428, -0.743286]], [161, [5.45017, 5.73622, -1.85555]],
                  [162, [5.63365, 6.26245, -1.85505]], [163, [6.1073, 6.76594, -1.94462]],
                  [164, [6.58044, 7.20559, -1.85469]], [165, [6.88931, 7.53961, -1.51406]],
                  [166, [7.10716, 7.66078, -1.04544]], [167, [7.19471, 7.51389, -0.59239]],
                  [168, [5.40772, 4.66524, 3.02514]], [169, [5.76931, 5.01291, 2.65931]],
                  [170, [6.14507, 5.2088, 2.16144]], [171, [6.27824, 5.38063, 1.43376]],
                  [172, [6.17431, 5.62542, 0.759444]], [173, [6.24094, 5.98304, 0.33088]],
                  [174, [6.67544, 6.4994, 0.0532598]], [175, [-2.6477, 4.65851, -0.662931]],
                  [176, [-2.71723, 4.72583, -0.337669]], [177, [-3.02974, 5.03001, 0.0133729]],
                  [178, [-3.55156, 5.4128, 0.457088]], [179, [-4.08555, 5.6588, 0.878288]],
                  [180, [-4.20689, 6.06137, 1.27083]], [181, [-3.94135, 6.61804, 1.64613]],
                  [182, [-3.90152, 5.41826, 3.96519]], [183, [-3.68639, 5.69672, 3.7975]],
                  [184, [-3.57372, 5.96746, 3.6043]], [185, [-3.50975, 6.24396, 3.36952]],
                  [186, [-3.38908, 6.56161, 3.08272]], [187, [-3.23099, 6.92618, 2.74989]],
                  [188, [-3.27483, 7.14141, 2.38829]], [189, [1.45619, -7.49005, -3.83906]],
                  [190, [-2.15714, 3.22855, 4.74324]], [191, [-3.20732, -16.3363, 0.593722]],
                  [192, [8.50918, 6.1379, -0.126037]], [193, [-1.3075, 10.5179, 0.0826635]],
                  [194, [6.66269, -11.5952, 0.976294]], [195, [6.18407, -10.885, 3.95382]],
                  [196, [4.6369, -16.5258, 3.13471]], [197, [-6.47456, -10.6289, -2.18081]],
                  [198, [-2.82653, 6.85526, 3.372]], [199, [-2.65245, 4.26594, -0.23955]],
                  [200, [6.45967, -11.2423, 3.81836]], [201, [1.33039, -11.5956, 4.72251]],
                  [202, [1.30475, 4.5572, -3.30185]], [203, [8.00107, -6.69582, 2.12858]],
                  [204, [4.57166, 6.984, 2.49627]], [205, [-3.24572, -12.1366, -3.56982]],
                  [206, [5.3204, 6.36013, -2.56745]], [207, [-3.11957, 7.73189, 2.69959]],
                  [208, [6.77177, 0.0625889, 4.49272]], [209, [6.94192, -4.53513, -1.62334]],
                  [210, [7.13623, 2.29023, 2.48835]], [211, [-5.82156, -11.0413, 0.905474]],
                  [212, [-1.63365, -0.816481, -2.63599]], [213, [-3.79753, -3.1284, 4.1384]],
                  [214, [-6.72222, 2.34786, 1.69348]], [215, [-0.365939, -17.3946, 3.7759]],
                  [216, [-2.86998, 8.92864, -2.32206]], [217, [-1.19507, -7.54906, -2.6852]],
                  [218, [4.65156, 2.46804, -4.03467]], [219, [3.35007, -14.7047, 0.201495]],
                  [220, [1.6206, 3.8501, 3.19007]], [221, [2.27385, 10.1786, 0.636264]],
                  [222, [-0.511457, -9.4981, 5.60078]], [223, [1.90472, -3.64936, 4.72947]],
                  [224, [-3.64124, -14.7226, 1.98156]], [225, [0.714248, -11.7933, -1.52495]],
                  [226, [-7.27783, -2.97639, 1.02711]], [227, [0.0551114, -15.631, 0.740704]],
                  [228, [4.08346, -6.60669, 4.23111]], [229, [-3.96676, -3.6568, -3.18453]],
                  [230, [0.128981, -15.0967, 4.90768]], [231, [5.1814, -0.697958, -2.3693]],
                  [232, [-2.24666, 3.46083, -1.55516]], [233, [-1.03731, 9.80536, -2.4258]],
                  [234, [2.76201, 7.5254, -2.57689]], [235, [-3.21442, 0.849207, -3.77201]],
                  [236, [-4.5522, 4.79028, 3.52668]], [237, [-4.2064, -13.7668, -2.8477]],
                  [238, [7.41965, 0.205489, 0.882005]], [239, [-7.04821, -1.17492, -1.75941]],
                  [240, [7.28529, -10.4271, 2.98472]], [241, [7.00561, -4.39045, 2.97423]],
                  [242, [2.43302, 1.91306, 4.44534]], [243, [2.09039, -17.1687, 0.520695]],
                  [244, [-3.27282, 1.6396, 3.67241]], [245, [-6.87723, -7.81655, 0.412325]],
                  [246, [5.25677, 8.8326, 0.858971]], [247, [-1.28577, -11.2257, 2.07694]],
                  [248, [0.805838, 8.11066, 0.90506]], [249, [-0.46974, -2.74816, 4.81187]],
                  [250, [-3.06642, 7.51852, -0.246379]], [251, [4.55288, 2.79781, 2.29269]],
                  [252, [4.04536, -8.45291, -2.82363]], [253, [-1.69131, -8.69729, 4.54945]],
                  [254, [7.44942, 3.06384, -0.812776]], [255, [-0.375084, 2.10788, -3.87666]],
                  [256, [-2.33075, -13.1125, 1.34638]], [257, [3.73976, -15.1661, 5.22367]],
                  [258, [-4.13958, -10.4225, 1.48909]], [259, [-6.57359, -4.40388, -2.5274]],
                  [260, [-1.19156, -17.5279, 2.70367]], [261, [1.48849, 0.940755, -3.11198]],
                  [262, [-6.25666, -8.51528, -2.26368]], [263, [5.42219, -14.6917, 0.904344]],
                  [264, [-5.30033, 2.91069, 2.77322]], [265, [-3.69181, 5.1199, 4.16583]],
                  [266, [5.23465, -10.0999, -0.279651]], [267, [3.30916, -9.50085, 4.15144]],
                  [268, [6.64312, -7.95079, 0.064867]], [269, [2.06641, -11.3195, -2.02518]],
                  [270, [-6.87761, -1.18354, 1.26735]], [271, [-1.93959, -3.56711, -3.96444]],
                  [272, [-0.33943, -13.7318, 2.4941]], [273, [3.44558, -13.2893, 5.10556]],
                  [274, [-3.73378, -8.56427, -2.31567]], [275, [-2.35109, -5.13952, 5.32983]],
                  [276, [6.42324, 0.543804, 2.58669]], [277, [7.86166, -5.16509, 0.692536]],
                  [278, [3.76085, -3.61315, -3.37012]], [279, [5.44298, -14.2463, 3.15755]],
                  [280, [-1.70985, -15.7899, 0.0519905]], [281, [2.26734, -13.5848, -1.39097]],
                  [282, [5.74778, 6.39146, 1.10414]], [283, [-2.11671, 9.79717, 1.08835]],
                  [284, [2.8608, 8.25119, 1.23121]], [285, [-1.18382, 4.3518, 3.89946]],
                  [286, [7.96713, 5.05793, 1.41253]], [287, [-6.69457, -4.65279, -1.21029]],
                  [288, [0.0191634, -9.11299, -2.26856]], [289, [-3.81062, -7.07655, 2.93881]],
                  [290, [-7.32947, 0.0447152, 1.78407]], [291, [1.69836, -8.23934, 4.66153]],
                  [292, [-6.6485, -10.8634, -0.11143]], [293, [-4.06035, -15.9321, 1.42343]],
                  [294, [4.5849, 7.70502, -0.677262]], [295, [-1.09886, -1.13732, 5.43579]],
                  [296, [2.70622, -0.301464, -3.82059]], [297, [-5.6857, -1.744, -2.71823]],
                  [298, [-5.81655, -12.8909, -1.16874]], [299, [0.289658, -18.1278, 2.42564]],
                  [300, [-4.47469, -6.57199, 2.10047]], [301, [0.112202, 10.0015, 0.627223]],
                  [302, [0.235416, 8.04662, -3.31171]], [303, [-2.24934, -5.91415, -2.4902]],
                  [304, [-2.55157, 4.50158, -2.19153]], [305, [6.43219, 3.07829, 2.6692]],
                  [306, [-3.97414, 5.64061, 1.87932]], [307, [-4.56586, 0.0207524, 4.42228]],
                  [308, [4.63573, -2.79558, 3.89731]], [309, [6.43056, -6.98187, 3.0528]],
                  [310, [-0.986888, -5.57974, 4.56781]], [311, [2.21565, 4.82825, 3.77766]],
                  [312, [-1.71112, -11.9039, -1.80275]], [313, [2.9143, -7.33767, -3.12538]],
                  [314, [3.40413, -13.6728, -0.739559]], [315, [7.51963, -2.20202, 0.395068]],
                  [316, [5.59617, -12.9598, 1.13681]], [317, [-2.42802, 6.61584, -0.938049]],
                  [318, [5.51021, -11.3324, -0.968232]], [319, [6.25447, 5.61217, -1.3508]],
                  [320, [-1.20197, 8.31877, -2.62206]], [321, [4.7415, 1.08838, 4.32509]],
                  [322, [5.97589, -3.48225, -1.75155]], [323, [-2.15625, -15.757, 0.921245]],
                  [324, [-2.94145, -6.93029, -3.58556]], [325, [2.64081, 5.92833, -2.84607]],
                  [326, [3.95925, -17.4688, 1.86022]], [327, [-3.52455, -14.873, 0.832899]],
                  [328, [-3.21377, -9.36567, 4.09077]], [329, [-4.48335, -7.68947, 1.74946]]]

    faces_list = [[0, [0, 21, 205]], [1, [205, 70, 0]], [2, [21, 22, 205]], [3, [22, 23, 205]], [4, [23, 24, 274]],
                  [5, [24, 25, 324]], [6, [25, 26, 229]], [7, [26, 27, 229]], [8, [27, 9, 229]], [9, [205, 71, 70]],
                  [10, [205, 72, 71]], [11, [205, 73, 72]], [12, [205, 74, 73]], [13, [312, 75, 74]],
                  [14, [312, 76, 75]], [15, [312, 12, 76]], [16, [28, 2, 35]], [17, [35, 304, 28]], [18, [304, 35, 36]],
                  [19, [304, 36, 37]], [20, [304, 37, 38]], [21, [304, 38, 39]], [22, [232, 39, 40]],
                  [23, [232, 40, 41]], [24, [202, 41, 10]], [25, [29, 28, 304]], [26, [30, 29, 304]],
                  [27, [31, 30, 232]], [28, [32, 31, 235]], [29, [33, 32, 235]], [30, [34, 33, 235]],
                  [31, [9, 34, 229]], [32, [3, 49, 218]], [33, [218, 42, 3]], [34, [49, 50, 218]], [35, [50, 51, 218]],
                  [36, [51, 52, 218]], [37, [52, 53, 261]], [38, [53, 54, 231]], [39, [54, 55, 231]],
                  [40, [55, 11, 278]], [41, [218, 43, 42]], [42, [218, 44, 43]], [43, [325, 45, 44]],
                  [44, [325, 46, 45]], [45, [325, 47, 46]], [46, [325, 48, 47]], [47, [202, 10, 48]], [48, [56, 1, 63]],
                  [49, [63, 269, 56]], [50, [269, 63, 64]], [51, [269, 64, 65]], [52, [269, 65, 66]],
                  [53, [269, 66, 67]], [54, [225, 67, 68]], [55, [225, 68, 69]], [56, [312, 69, 12]],
                  [57, [57, 56, 269]], [58, [58, 57, 269]], [59, [59, 58, 269]], [60, [60, 59, 252]],
                  [61, [61, 60, 252]], [62, [62, 61, 313]], [63, [11, 62, 278]], [64, [4, 77, 247]],
                  [65, [247, 126, 4]], [66, [77, 78, 247]], [67, [78, 79, 247]], [68, [79, 80, 247]],
                  [69, [80, 81, 201]], [70, [81, 82, 201]], [71, [82, 83, 201]], [72, [83, 13, 201]],
                  [73, [247, 127, 126]], [74, [328, 128, 127]], [75, [289, 129, 128]], [76, [289, 130, 129]],
                  [77, [275, 131, 130]], [78, [275, 132, 131]], [79, [213, 16, 132]], [80, [84, 5, 91]],
                  [81, [91, 200, 84]], [82, [200, 91, 92]], [83, [195, 92, 93]], [84, [273, 93, 94]],
                  [85, [267, 94, 95]], [86, [267, 95, 96]], [87, [228, 96, 97]], [88, [228, 97, 14]],
                  [89, [85, 84, 200]], [90, [86, 85, 195]], [91, [87, 86, 195]], [92, [88, 87, 195]],
                  [93, [89, 88, 273]], [94, [90, 89, 273]], [95, [13, 90, 273]], [96, [7, 105, 251]],
                  [97, [251, 98, 7]], [98, [105, 106, 251]], [99, [106, 107, 311]], [100, [107, 108, 311]],
                  [101, [108, 109, 311]], [102, [109, 110, 311]], [103, [110, 111, 285]], [104, [111, 15, 285]],
                  [105, [251, 99, 98]], [106, [251, 100, 99]], [107, [321, 101, 100]], [108, [321, 102, 101]],
                  [109, [223, 103, 102]], [110, [308, 104, 103]], [111, [308, 14, 104]], [112, [112, 6, 119]],
                  [113, [119, 265, 112]], [114, [265, 119, 120]], [115, [265, 120, 121]], [116, [190, 121, 122]],
                  [117, [244, 122, 123]], [118, [307, 123, 124]], [119, [307, 124, 125]], [120, [213, 125, 16]],
                  [121, [113, 112, 265]], [122, [114, 113, 265]], [123, [115, 114, 265]], [124, [116, 115, 285]],
                  [125, [117, 116, 285]], [126, [118, 117, 285]], [127, [15, 118, 285]], [128, [0, 70, 237]],
                  [129, [237, 154, 0]], [130, [70, 71, 237]], [131, [71, 72, 237]], [132, [72, 73, 280]],
                  [133, [73, 74, 280]], [134, [74, 75, 280]], [135, [75, 76, 227]], [136, [76, 12, 227]],
                  [137, [237, 155, 154]], [138, [237, 156, 155]], [139, [237, 157, 156]], [140, [237, 158, 157]],
                  [141, [327, 159, 158]], [142, [327, 160, 159]], [143, [327, 18, 160]], [144, [63, 1, 133]],
                  [145, [133, 314, 63]], [146, [314, 133, 134]], [147, [314, 134, 135]], [148, [314, 135, 136]],
                  [149, [314, 136, 137]], [150, [314, 137, 138]], [151, [263, 138, 139]], [152, [263, 139, 17]],
                  [153, [64, 63, 314]], [154, [65, 64, 281]], [155, [66, 65, 281]], [156, [67, 66, 281]],
                  [157, [68, 67, 219]], [158, [69, 68, 227]], [159, [12, 69, 227]], [160, [5, 84, 279]],
                  [161, [279, 140, 5]], [162, [84, 85, 279]], [163, [85, 86, 279]], [164, [86, 87, 279]],
                  [165, [87, 88, 257]], [166, [88, 89, 257]], [167, [89, 90, 230]], [168, [90, 13, 230]],
                  [169, [279, 141, 140]], [170, [279, 142, 141]], [171, [279, 143, 142]], [172, [263, 144, 143]],
                  [173, [263, 145, 144]], [174, [263, 146, 145]], [175, [263, 17, 146]], [176, [77, 4, 147]],
                  [177, [147, 256, 77]], [178, [256, 147, 148]], [179, [256, 148, 149]], [180, [256, 149, 150]],
                  [181, [256, 150, 151]], [182, [327, 151, 152]], [183, [327, 152, 153]], [184, [327, 153, 18]],
                  [185, [78, 77, 256]], [186, [79, 78, 256]], [187, [80, 79, 272]], [188, [81, 80, 272]],
                  [189, [82, 81, 272]], [190, [83, 82, 230]], [191, [13, 83, 230]], [192, [1, 56, 318]],
                  [193, [318, 133, 1]], [194, [56, 57, 266]], [195, [57, 58, 266]], [196, [58, 59, 209]],
                  [197, [59, 60, 209]], [198, [60, 61, 209]], [199, [61, 62, 322]], [200, [62, 11, 322]],
                  [201, [318, 134, 133]], [202, [318, 135, 134]], [203, [318, 136, 135]], [204, [318, 137, 136]],
                  [205, [318, 138, 137]], [206, [318, 139, 138]], [207, [316, 17, 139]], [208, [49, 3, 161]],
                  [209, [161, 319, 49]], [210, [319, 161, 162]], [211, [319, 162, 163]], [212, [319, 163, 164]],
                  [213, [319, 164, 165]], [214, [192, 165, 166]], [215, [192, 166, 167]], [216, [192, 167, 19]],
                  [217, [50, 49, 319]], [218, [51, 50, 319]], [219, [52, 51, 254]], [220, [53, 52, 254]],
                  [221, [54, 53, 254]], [222, [55, 54, 238]], [223, [11, 55, 238]], [224, [7, 98, 305]],
                  [225, [305, 168, 7]], [226, [98, 99, 305]], [227, [99, 100, 305]], [228, [100, 101, 208]],
                  [229, [101, 102, 208]], [230, [102, 103, 208]], [231, [103, 104, 208]], [232, [104, 14, 241]],
                  [233, [305, 169, 168]], [234, [305, 170, 169]], [235, [286, 171, 170]], [236, [286, 172, 171]],
                  [237, [286, 173, 172]], [238, [192, 174, 173]], [239, [192, 19, 174]], [240, [91, 5, 140]],
                  [241, [140, 240, 91]], [242, [240, 140, 141]], [243, [240, 141, 142]], [244, [240, 142, 143]],
                  [245, [240, 143, 144]], [246, [316, 144, 145]], [247, [316, 145, 146]], [248, [316, 146, 17]],
                  [249, [92, 91, 240]], [250, [93, 92, 240]], [251, [94, 93, 240]], [252, [95, 94, 309]],
                  [253, [96, 95, 309]], [254, [97, 96, 241]], [255, [14, 97, 241]], [256, [3, 42, 206]],
                  [257, [206, 161, 3]], [258, [42, 43, 206]], [259, [43, 44, 206]], [260, [44, 45, 234]],
                  [261, [45, 46, 234]], [262, [46, 47, 234]], [263, [47, 48, 302]], [264, [48, 10, 302]],
                  [265, [206, 162, 161]], [266, [206, 163, 162]], [267, [206, 164, 163]], [268, [206, 165, 164]],
                  [269, [246, 166, 165]], [270, [246, 167, 166]], [271, [204, 19, 167]], [272, [35, 2, 175]],
                  [273, [175, 317, 35]], [274, [317, 175, 176]], [275, [317, 176, 177]], [276, [317, 177, 178]],
                  [277, [317, 178, 179]], [278, [250, 179, 180]], [279, [250, 180, 181]], [280, [250, 181, 20]],
                  [281, [36, 35, 317]], [282, [37, 36, 317]], [283, [38, 37, 317]], [284, [39, 38, 320]],
                  [285, [40, 39, 320]], [286, [41, 40, 320]], [287, [10, 41, 320]], [288, [6, 112, 198]],
                  [289, [198, 182, 6]], [290, [112, 113, 198]], [291, [113, 114, 198]], [292, [114, 115, 248]],
                  [293, [115, 116, 248]], [294, [116, 117, 248]], [295, [117, 118, 248]], [296, [118, 15, 284]],
                  [297, [198, 183, 182]], [298, [198, 184, 183]], [299, [207, 185, 184]], [300, [207, 186, 185]],
                  [301, [207, 187, 186]], [302, [207, 188, 187]], [303, [250, 20, 188]], [304, [105, 7, 168]],
                  [305, [168, 282, 105]], [306, [282, 168, 169]], [307, [282, 169, 170]], [308, [282, 170, 171]],
                  [309, [282, 171, 172]], [310, [282, 172, 173]], [311, [282, 173, 174]], [312, [204, 174, 19]],
                  [313, [106, 105, 282]], [314, [107, 106, 282]], [315, [108, 107, 282]], [316, [109, 108, 204]],
                  [317, [110, 109, 204]], [318, [111, 110, 284]], [319, [15, 111, 284]], [320, [2, 28, 199]],
                  [321, [199, 175, 2]], [322, [28, 29, 199]], [323, [29, 30, 199]], [324, [30, 31, 239]],
                  [325, [31, 32, 239]], [326, [32, 33, 297]], [327, [33, 34, 297]], [328, [34, 9, 259]],
                  [329, [199, 176, 175]], [330, [199, 177, 176]], [331, [199, 178, 177]], [332, [199, 179, 178]],
                  [333, [306, 180, 179]], [334, [306, 181, 180]], [335, [306, 20, 181]], [336, [21, 0, 154]],
                  [337, [154, 298, 21]], [338, [298, 154, 155]], [339, [298, 155, 156]], [340, [298, 156, 157]],
                  [341, [298, 157, 158]], [342, [298, 158, 159]], [343, [298, 159, 160]], [344, [211, 160, 18]],
                  [345, [22, 21, 298]], [346, [23, 22, 197]], [347, [24, 23, 197]], [348, [25, 24, 197]],
                  [349, [26, 25, 262]], [350, [27, 26, 262]], [351, [9, 27, 259]], [352, [4, 126, 258]],
                  [353, [258, 147, 4]], [354, [126, 127, 258]], [355, [127, 128, 329]], [356, [128, 129, 329]],
                  [357, [129, 130, 300]], [358, [130, 131, 300]], [359, [131, 132, 226]], [360, [132, 16, 270]],
                  [361, [258, 148, 147]], [362, [211, 149, 148]], [363, [211, 150, 149]], [364, [211, 151, 150]],
                  [365, [211, 152, 151]], [366, [211, 153, 152]], [367, [211, 18, 153]], [368, [119, 6, 182]],
                  [369, [182, 236, 119]], [370, [236, 182, 183]], [371, [236, 183, 184]], [372, [236, 184, 185]],
                  [373, [236, 185, 186]], [374, [236, 186, 187]], [375, [236, 187, 188]], [376, [306, 188, 20]],
                  [377, [120, 119, 236]], [378, [121, 120, 264]], [379, [122, 121, 264]], [380, [123, 122, 264]],
                  [381, [124, 123, 290]], [382, [125, 124, 290]], [383, [16, 125, 270]], [384, [240, 309, 94]],
                  [385, [209, 266, 58]], [386, [93, 273, 195]], [387, [195, 273, 88]], [388, [219, 227, 68]],
                  [389, [230, 257, 89]], [390, [300, 329, 129]], [391, [262, 259, 27]], [392, [184, 198, 207]],
                  [393, [248, 198, 114]], [394, [239, 199, 30]], [395, [179, 199, 306]], [396, [200, 195, 85]],
                  [397, [92, 195, 200]], [398, [130, 289, 275]], [399, [14, 308, 228]], [400, [278, 231, 55]],
                  [401, [232, 235, 31]], [402, [208, 305, 100]], [403, [194, 268, 203]], [404, [167, 246, 204]],
                  [405, [204, 284, 110]], [406, [274, 205, 23]], [407, [74, 205, 312]], [408, [234, 206, 44]],
                  [409, [165, 206, 246]], [410, [207, 198, 283]], [411, [188, 207, 250]], [412, [276, 241, 315]],
                  [413, [241, 208, 104]], [414, [238, 322, 11]], [415, [315, 241, 322]], [416, [170, 305, 286]],
                  [417, [254, 238, 54]], [418, [160, 211, 298]], [419, [259, 262, 245]], [420, [235, 229, 34]],
                  [421, [255, 296, 271]], [422, [102, 321, 223]], [423, [125, 213, 307]], [424, [239, 214, 199]],
                  [425, [290, 270, 125]], [426, [256, 272, 79]], [427, [243, 299, 227]], [428, [302, 234, 47]],
                  [429, [207, 283, 250]], [430, [288, 225, 205]], [431, [296, 189, 217]], [432, [202, 261, 255]],
                  [433, [44, 218, 325]], [434, [143, 279, 263]], [435, [299, 243, 326]], [436, [285, 311, 110]],
                  [437, [220, 285, 249]], [438, [301, 221, 302]], [439, [284, 248, 118]], [440, [223, 222, 291]],
                  [441, [127, 247, 328]], [442, [295, 244, 213]], [443, [310, 222, 223]], [444, [158, 237, 327]],
                  [445, [224, 323, 230]], [446, [225, 288, 313]], [447, [269, 252, 59]], [448, [287, 245, 300]],
                  [449, [214, 239, 270]], [450, [323, 280, 260]], [451, [280, 237, 72]], [452, [94, 267, 273]],
                  [453, [291, 222, 201]], [454, [229, 324, 25]], [455, [217, 271, 296]], [456, [215, 257, 230]],
                  [457, [215, 230, 323]], [458, [261, 218, 52]], [459, [261, 202, 218]], [460, [41, 202, 232]],
                  [461, [255, 232, 202]], [462, [233, 216, 193]], [463, [320, 302, 10]], [464, [294, 234, 302]],
                  [465, [234, 294, 206]], [466, [235, 232, 255]], [467, [229, 235, 212]], [468, [214, 306, 199]],
                  [469, [236, 264, 120]], [470, [280, 191, 237]], [471, [293, 327, 237]], [472, [210, 276, 238]],
                  [473, [238, 254, 210]], [474, [259, 297, 34]], [475, [8, 270, 239]], [476, [144, 316, 240]],
                  [477, [194, 203, 240]], [478, [309, 241, 96]], [479, [277, 322, 241]], [480, [242, 220, 249]],
                  [481, [311, 251, 106]], [482, [243, 219, 196]], [483, [219, 243, 227]], [484, [190, 244, 295]],
                  [485, [122, 244, 190]], [486, [329, 300, 245]], [487, [292, 245, 262]], [488, [284, 204, 246]],
                  [489, [294, 302, 221]], [490, [201, 247, 80]], [491, [247, 201, 222]], [492, [221, 301, 248]],
                  [493, [198, 248, 283]], [494, [223, 249, 310]], [495, [321, 249, 223]], [496, [317, 320, 38]],
                  [497, [250, 193, 216]], [498, [100, 251, 321]], [499, [251, 220, 242]], [500, [189, 313, 288]],
                  [501, [313, 278, 62]], [502, [222, 253, 247]], [503, [222, 275, 253]], [504, [319, 254, 51]],
                  [505, [286, 210, 254]], [506, [255, 212, 235]], [507, [271, 212, 255]], [508, [256, 224, 272]],
                  [509, [151, 327, 256]], [510, [257, 279, 87]], [511, [196, 257, 299]], [512, [148, 258, 211]],
                  [513, [245, 292, 329]], [514, [239, 259, 8]], [515, [245, 287, 259]], [516, [215, 299, 257]],
                  [517, [215, 323, 260]], [518, [189, 296, 231]], [519, [231, 261, 53]], [520, [197, 292, 262]],
                  [521, [197, 262, 25]], [522, [263, 196, 219]], [523, [138, 263, 314]], [524, [264, 290, 123]],
                  [525, [306, 214, 264]], [526, [121, 190, 265]], [527, [265, 285, 115]], [528, [266, 268, 194]],
                  [529, [139, 318, 316]], [530, [291, 228, 223]], [531, [96, 228, 267]], [532, [277, 268, 209]],
                  [533, [266, 209, 268]], [534, [67, 225, 269]], [535, [313, 269, 225]], [536, [270, 8, 226]],
                  [537, [270, 226, 132]], [538, [271, 217, 303]], [539, [212, 271, 229]], [540, [272, 230, 82]],
                  [541, [230, 272, 224]], [542, [273, 201, 13]], [543, [201, 273, 291]], [544, [324, 274, 24]],
                  [545, [217, 205, 274]], [546, [132, 275, 213]], [547, [213, 310, 249]], [548, [241, 276, 208]],
                  [549, [210, 208, 276]], [550, [241, 309, 277]], [551, [268, 277, 203]], [552, [231, 278, 189]],
                  [553, [278, 313, 189]], [554, [196, 263, 279]], [555, [279, 257, 196]], [556, [280, 227, 299]],
                  [557, [227, 280, 75]], [558, [281, 219, 67]], [559, [314, 281, 64]], [560, [174, 204, 282]],
                  [561, [282, 204, 108]], [562, [283, 248, 193]], [563, [193, 250, 283]], [564, [248, 284, 221]],
                  [565, [246, 221, 284]], [566, [190, 249, 285]], [567, [285, 265, 190]], [568, [192, 286, 254]],
                  [569, [173, 286, 192]], [570, [287, 226, 8]], [571, [287, 8, 259]], [572, [288, 217, 189]],
                  [573, [205, 217, 288]], [574, [128, 328, 289]], [575, [289, 253, 275]], [576, [290, 214, 270]],
                  [577, [264, 214, 290]], [578, [291, 267, 228]], [579, [267, 291, 273]], [580, [211, 292, 197]],
                  [581, [292, 211, 258]], [582, [323, 224, 293]], [583, [237, 191, 293]], [584, [206, 294, 246]],
                  [585, [221, 246, 294]], [586, [249, 190, 295]], [587, [213, 249, 295]], [588, [261, 231, 296]],
                  [589, [261, 296, 255]], [590, [297, 239, 32]], [591, [259, 239, 297]], [592, [298, 211, 197]],
                  [593, [298, 197, 22]], [594, [280, 299, 260]], [595, [260, 299, 215]], [596, [226, 287, 300]],
                  [597, [226, 300, 131]], [598, [301, 193, 248]], [599, [301, 233, 193]], [600, [302, 233, 301]],
                  [601, [302, 320, 233]], [602, [324, 229, 303]], [603, [303, 229, 271]], [604, [39, 232, 304]],
                  [605, [304, 232, 30]], [606, [210, 286, 305]], [607, [305, 208, 210]], [608, [188, 306, 236]],
                  [609, [236, 306, 264]], [610, [244, 307, 213]], [611, [123, 307, 244]], [612, [103, 223, 308]],
                  [613, [308, 223, 228]], [614, [240, 203, 309]], [615, [203, 277, 309]], [616, [275, 222, 310]],
                  [617, [275, 310, 213]], [618, [220, 251, 311]], [619, [311, 285, 220]], [620, [69, 312, 225]],
                  [621, [312, 205, 225]], [622, [252, 313, 61]], [623, [252, 269, 313]], [624, [219, 314, 263]],
                  [625, [314, 219, 281]], [626, [315, 238, 276]], [627, [315, 322, 238]], [628, [194, 316, 318]],
                  [629, [316, 194, 240]], [630, [216, 317, 250]], [631, [179, 250, 317]], [632, [266, 318, 56]],
                  [633, [194, 318, 266]], [634, [254, 319, 192]], [635, [165, 192, 319]], [636, [320, 216, 233]],
                  [637, [317, 216, 320]], [638, [249, 321, 242]], [639, [242, 321, 251]], [640, [322, 277, 209]],
                  [641, [322, 209, 61]], [642, [323, 293, 191]], [643, [280, 323, 191]], [644, [303, 217, 324]],
                  [645, [274, 324, 217]], [646, [325, 218, 202]], [647, [48, 325, 202]], [648, [196, 299, 326]],
                  [649, [196, 326, 243]], [650, [327, 293, 224]], [651, [327, 224, 256]], [652, [253, 328, 247]],
                  [653, [289, 328, 253]], [654, [329, 258, 127]], [655, [258, 329, 292]]]

    mesh.SetNumVerts(len(verts_list))  # The number of faces and vertices is calculated automatically
    mesh.SetNumFaces(len(faces_list))

    for vert in verts_list:  # For every vertex position from list save its data to mesh
        mesh.SetVert(vert[0], MaxPlus.Point3(vert[1][0], vert[1][1], vert[1][2]))

    for face in faces_list:  # For every face from list save its data to mesh
        mesh.GetFace(face[0]).SetVerts(face[1][0], face[1][1], face[1][2])
        mesh.GetFace(face[0]).SetEdgeVisFlags(1, 1, 0)

    mesh.InvalidateGeomCache()
    mesh.InvalidateTopologyCache()


def create_palm(diameter, segs_num, leafs_num, bending, id_num, anim_start, anim_end):
    """
    Function creates a single palm tree.
    This function was created to show how to create basic geometry objects, use instances and use modificators.

    :param diameter: float - inner diameter of pine
    :param segs_num: int - number of segments of the pine
    :param leafs_num: int - number of leafs
    :param bending: float - how much bended the pine is
    :param id_num: int - ID of the tree
    :param anim_start: int - Starting frame of the tree animation
    :param anim_end: int - Ending frame of the tree animation
    """

    r1 = diameter / 2
    r2 = r1 * 1.3
    h = diameter  # Height of each segment
    keyframe_interval = (anim_end - anim_start) / (segs_num + 1.0)  # interval of scale keframes of the pine segments

    anim_start *= TICKS  # Convert frames to the internal 3Ds Max time unit.
    anim_end *= TICKS  # Need to convert now, because the number of segments is probably
    keyframe_interval *= TICKS  # grater then the number of frames between the start and the end o the animation of tree

    keyframe_list = range(anim_start, anim_end, int(keyframe_interval))  # list of times of keyframes for the pine
    # and leafs. Equal time intervals.

    keyframe_list.reverse()  # Because the pop() will be used and the first frame should be the smallest number
    MaxPlus.SelectionManager.ClearNodeSelection()

    segment = MaxPlus.Factory.CreateGeomObject(MaxPlus.ClassIds.Cone)  # Basic geometry - cone object is created
    parameters = segment.ParameterBlock  # The parameters of object can be accessed by Parameter Block
    parameters.radius1.Value, parameters.radius2.Value, parameters.height.Value = (r1, r2, h)
    # To query the Parameters available in the ParameterBlock that you set for your object, do as follows:
    # for p in obj.ParameterBlock.Parameters:
    #     print p.Name, p.Value

    segments_tab = MaxPlus.INodeTab()  # Save the nodes of pine segments and leafs to the table.
    # Will be used to assign one bend modificator to all of the segments

    for i in xrange(segs_num):
        # Create segments of pine of the palm tree

        segment_node = MaxPlus.Factory.CreateNode(segment)  # Create a node (Instance) with segment (Cone) geometry
        # The nodes at the top of the tree should be smaller then those at the bottom:
        segment_node.Scale(MaxPlus.Point3(1.0 - (i / (segs_num * 4.0)), 1.0 - (i / (segs_num * 4.0)), 1))

        segment_node.SetPositionZ(h * i)  # Every node should be H higher then the last one
        segment_node.SetName('Palm_element_' + str(id_num) + '_' + str(i))  # Set the name of the node with proper ID
        segments_tab.Append(segment_node)  # Append to the nodes table
        anim_start_frame = keyframe_list.pop()  # Pop one time from the keyframe times list
        set_scale_keys(target=segment_node, keyframes=[[0.001, anim_start_frame],
                                                       [1.2, anim_start_frame + keyframe_interval],
                                                       [1, anim_start_frame + 2 * keyframe_interval]],
                       multiply_by_ticks=False)
        try:  # If the segment is not the first segment of the tree then it should be parented to the previous one.
            segment_node.Parent = root  # if there is not old_segment_node the command will fail
        except:  # If the function failed then this is a first node of the tree and will not have any parent
            land = MaxPlus.INode.GetINodeByName("land")
            segment_node.Parent = land
            root = segment_node

    # The leaf will be created from saved vertex data in a similar way to cloud.
    geom = MaxPlus.Factory.CreateGeomObject(MaxPlus.ClassIds.TriMeshGeometry)
    # noinspection PyProtectedMember
    tri = MaxPlus.TriObject._CastFrom(geom)
    mesh = tri.GetMesh()
    verts_list = [[0, [0.0874634, 0.283682, -0.150049]], [1, [-9.33334, 3.45312, -5.19915]],
                  [2, [-0.0979366, -0.242619, -0.151449]], [3, [0.0756626, 0.288981, 0.00435066]],
                  [4, [-0.110037, -0.237219, 0.00305176]], [5, [-0.0341358, 0.0332813, 0.222252]],
                  [6, [-0.046236, 0.0384817, 0.376751]], [7, [-2.00844, -0.0782185, -0.04245]],
                  [8, [-1.49184, 1.38118, -0.0476494]], [9, [-1.51604, 1.39538, 0.200851]],
                  [10, [-2.03964, -0.0789185, 0.205851]], [11, [-1.79314, 0.661982, 0.356852]],
                  [12, [-8.51614, 2.95795, -3.08655]], [13, [-8.65224, 1.73258, -3.67535]],
                  [14, [-7.77134, 3.93545, -3.64315]], [15, [-7.89874, 3.98053, -3.41335]],
                  [16, [-8.77254, 1.77508, -3.43515]], [17, [-8.38964, 2.89923, -3.33135]],
                  [18, [-1.81954, 0.668982, 0.60585]], [19, [-5.86674, 0.829681, -0.820549]],
                  [20, [-5.03134, 3.19562, -0.787249]], [21, [-5.10854, 3.23514, -0.531349]],
                  [22, [-5.94654, 0.870181, -0.570749]], [23, [-5.56024, 2.07138, -0.438848]],
                  [24, [-5.63774, 2.11408, -0.182249]], [25, [-7.35774, 1.29268, -2.00885]],
                  [26, [-6.54364, 3.59313, -1.90675]], [27, [-6.65514, 3.64373, -1.65775]],
                  [28, [-7.46144, 1.34048, -1.75845]], [29, [-7.10164, 2.51205, -1.60085]],
                  [30, [-3.83754, 1.37038, 0.50765]], [31, [-4.09794, 0.257582, -0.106649]],
                  [32, [-3.33404, 2.40815, -0.13835]], [33, [-3.38054, 2.42888, 0.109451]],
                  [34, [-4.14974, 0.269781, 0.141151]], [35, [-3.78934, 1.35658, 0.259151]],
                  [36, [-7.21234, 2.56052, -1.34435]], [37, [-8.70384, 4.0245, -4.67165]],
                  [38, [-9.38574, 2.48178, -4.54065]], [39, [-9.16784, 3.28523, -4.39535]],
                  [40, [-9.32104, 2.46601, -4.65515]], [41, [-8.76504, 4.03897, -4.55925]],
                  [42, [-9.10294, 3.26697, -4.51255]]]

    faces_list = [[0, [0, 5, 8]], [1, [3, 9, 6]], [2, [0, 8, 3]], [3, [1, 40, 38]], [4, [2, 5, 4]], [5, [5, 2, 11]],
                  [6, [1, 38, 39]], [7, [5, 0, 6]], [8, [17, 37, 14]], [9, [15, 39, 12]], [10, [37, 41, 15]],
                  [11, [7, 2, 10]], [12, [40, 42, 17]], [13, [10, 4, 18]], [14, [11, 32, 8]], [15, [9, 33, 18]],
                  [16, [8, 32, 9]], [17, [13, 25, 16]], [18, [7, 31, 11]], [19, [16, 28, 12]], [20, [23, 29, 20]],
                  [21, [21, 36, 24]], [22, [20, 27, 21]], [23, [19, 34, 22]], [24, [19, 29, 23]], [25, [22, 30, 24]],
                  [26, [35, 20, 32]], [27, [33, 21, 30]], [28, [32, 20, 33]], [29, [25, 19, 28]], [30, [31, 19, 35]],
                  [31, [28, 22, 36]], [32, [29, 17, 26]], [33, [27, 12, 36]], [34, [26, 15, 27]], [35, [31, 10, 34]],
                  [36, [25, 17, 29]], [37, [34, 18, 30]], [38, [40, 13, 38]], [39, [38, 16, 12]], [40, [42, 1, 37]],
                  [41, [41, 1, 39]], [42, [37, 1, 41]], [43, [40, 1, 42]], [44, [5, 11, 8]], [45, [9, 18, 6]],
                  [46, [8, 9, 3]], [47, [5, 6, 4]], [48, [2, 7, 11]], [49, [0, 3, 6]], [50, [17, 42, 37]],
                  [51, [15, 41, 39]], [52, [15, 14, 37]], [53, [2, 4, 10]], [54, [17, 13, 40]], [55, [4, 6, 18]],
                  [56, [11, 35, 32]], [57, [33, 30, 18]], [58, [32, 33, 9]], [59, [25, 28, 16]], [60, [31, 35, 11]],
                  [61, [28, 36, 12]], [62, [29, 26, 20]], [63, [21, 27, 36]], [64, [20, 26, 27]], [65, [19, 31, 34]],
                  [66, [19, 25, 29]], [67, [22, 34, 30]], [68, [35, 23, 20]], [69, [21, 24, 30]], [70, [20, 21, 33]],
                  [71, [19, 22, 28]], [72, [19, 23, 35]], [73, [22, 24, 36]], [74, [17, 14, 26]], [75, [27, 15, 12]],
                  [76, [26, 14, 15]], [77, [31, 7, 10]], [78, [25, 13, 17]], [79, [34, 10, 18]], [80, [13, 16, 38]],
                  [81, [12, 39, 38]]]

    mesh.SetNumVerts(len(verts_list))
    mesh.SetNumFaces(len(faces_list))

    for vert in verts_list:
        mesh.SetVert(vert[0], MaxPlus.Point3(vert[1][0], vert[1][1], vert[1][2]))

    for face in faces_list:
        mesh.GetFace(face[0]).SetVerts(face[1][0], face[1][1], face[1][2])
        mesh.GetFace(face[0]).SetEdgeVisFlags(1, 1, 0)
    mesh.InvalidateGeomCache()
    mesh.InvalidateTopologyCache()

    anim_start_frame = keyframe_list.pop()

    for rot_z in leafs_rotations(number_of_leafs=leafs_num):  # Leafs should be distributed around the pine.
        leaf = MaxPlus.Factory.CreateNode(tri)
        leaf.SetName("leaf_" + str(id) + '_' + str(i))
        leaf.Position = segment_node.Position
        leaf.Move(MaxPlus.Point3(0, 0, 3 * h))

        rotation = leaf.GetWorldRotation()
        random.seed()
        rotation.SetEuler(random.uniform(-math.pi / 15, math.pi / 15), random.uniform(-math.pi / 8, math.pi / 10),
                          rot_z)  # The rotation can be set with a number of ways. Here, the current rotation is read
        # and modified as Euler. Also, the quaternion can be used with Rotate function.

        leaf.SetWorldRotation(rotation)
        set_scale_keys(target=leaf, keyframes=[[0.001, anim_start_frame], [1, anim_start_frame + keyframe_interval]],
                       multiply_by_ticks=False)
        leaf.Parent = segment_node
        leaf.Scale(MaxPlus.Point3(0.9, 0.9, 0.9))
        segments_tab.Append(leaf)
        i += 1

    MaxPlus.SelectionManager.SelectNodes(segments_tab)  # Select the nodes in the table
    bend = MaxPlus.Factory.CreateObjectModifier(MaxPlus.ClassIds.Bend)  # Create the bend modifier
    bend.ParameterBlock.BendAngle.Value = bending  # Modify the parameters of the modifier
    MaxPlus.ModifierPanel.AddToSelection(bend)  # Assign a one bend modifier to selected nodes

    return root


def append_material_by_prefix(prefix, material, node=MaxPlus.Core.GetRootNode()):
    """
    Recursive function that iterates thought the scene graph and applies material to nodes with chosen prefix

    :param prefix: str - chosen prefix
    :param material: MaxPlus.Mtl - material to append
    :param node: MaxPlus.INode - current node
    """

    if str(node.Name).startswith(prefix):
        node.Material = material
    for c in node.Children:
        append_material_by_prefix(prefix, material, c)


#
#
# Main functions of the script:
#
#


def prepare_scene(path):
    """
    The function sets the basic parameters of the scene: time range, tangent type of keyframes and render settings.

    :param path: string - The directory with necessary files
    """

    time_range = MaxPlus.Animation.GetAnimRange()  # Get and modify the animation time range
    time_range.SetEnd(260 * TICKS)
    time_range.SetStart(0)
    MaxPlus.Animation.SetRange(time_range)

    # Set tangent type to fast
    MaxPlus.Animation.SetDefaultTangentType(3, 3)
    MaxPlus.Animation.SetAnimateButtonState(False)  # Make sure, that the AutoKey button is disabled

    # Load the render settings with a use of MaxScript.
    # MaxScript commands can be run from Python script with a use of the MaxPlus.Core.EvalMAXScript() function.
    # The data returned by the MaxScript command can also be accessed.
    MaxPlus.Core.EvalMAXScript('renderPresets.LoadAll 0 ("' + path.replace("\\", "/") + '/render_settings_3DSMax.rps")')

    image_file = MaxPlus.AssetManager.CreateAsset(path.replace("\\", "/") + '/bg.bmp')  # Load background image as asset
    bitmap = MaxPlus.Factory.CreateDefaultBitmapTex()  # create bitmap texture
    bitmap.SetMap(image_file)
    MaxPlus.Environment.SetMap(bitmap)  # set texture as environment
    MaxPlus.Core.EvalMAXScript(
        '''
        environmentmap.coords.mappingType = 1
        environmentmap.coords.mapping = 3
        '''
    )  # The author of this script failed to set the mapping type to screen with Python API.
    # MaxScript came to the rescue


def import_and_animate_basic_meshes(path):
    """
    This function imports some objects and animates them.
    It was created to show how to import objects and present one way of creating keyframes of animation.

    :param path: string - The directory with necessary files
    """

    MaxPlus.FileManager.Import(path + '\water.obj', True)  # Import an obj file
    water = MaxPlus.INode.GetINodeByName("water")  # Select the imported object by name
    set_scale_keys(target=water, keyframes=[[0.001, 1], [1, 9]])  # Set the animation keys

    MaxPlus.FileManager.Import(path + '\land.obj', True)
    land = MaxPlus.INode.GetINodeByName("land")
    set_scale_keys(target=land, keyframes=[[0.001, 8], [1, 11]])


def create_shark_and_cloud():
    """
    Creates meshes from vertex and face data.
    Two functions are used: one is easier to read an one is more useful.
    Similar functions can be used in importer plugin.
    """

    geom = MaxPlus.Factory.CreateGeomObject(MaxPlus.ClassIds.TriMeshGeometry)
    # noinspection PyProtectedMember
    tri = MaxPlus.TriObject._CastFrom(geom)
    mesh = tri.GetMesh()
    make_shark_mesh(mesh)  # The simpler function that creates mesh based on saved data
    shark = MaxPlus.Factory.CreateNode(tri)  # Create a node
    shark.SetName("shark")  # Set the name of the node

    set_scale_keys(target=shark, keyframes=[[0.001, 9], [1, 15]])
    shark.Position = MaxPlus.Point3(-9.18464, 54.9695, -4)

    # Create complex mesh: cloud
    geom = MaxPlus.Factory.CreateGeomObject(MaxPlus.ClassIds.TriMeshGeometry)
    # noinspection PyProtectedMember
    tri = MaxPlus.TriObject._CastFrom(geom)
    mesh = tri.GetMesh()
    make_cloud_mesh(mesh)  # The more compact function that creates mesh based on saved data
    cloud = MaxPlus.Factory.CreateNode(tri)
    cloud.SetName("Cloud")

    set_scale_keys(target=cloud, keyframes=[[0.001, 22], [1.1, 27], [1, 29]])
    cloud.Position = MaxPlus.Point3(2.409, -39.500, 31)
    set_position_keys(target=cloud, keyframes=[[[2.409, -39.500, 31.7], 29, [5, 5]],
                                               [[2.409, -39.500, 33], 67, [5, 5]],
                                               [[2.409, -39.500, 32.3], 115, [5, 5]],
                                               [[2.409, -39.500, 31.5], 163, [5, 5]],
                                               [[2.409, -39.500, 32.3], 210, [5, 5]],
                                               [[2.409, -39.500, 31.4], 240, [5, 5]]])


def create_chest():
    """
    Function creates an object with a use of macro recorded frm 3Ds max.
    This function shows how to use macros. Macros are actions recorded with a MaxScript Listener and they can be
    evaluated as MaxScripts. Macros are a very simple way of creating simple scripts.
    """

    recorded_macro = '''

Box lengthsegs:1 widthsegs:1 heightsegs:1 length:34.5477 width:60.1759 height:25 mapcoords:on pos:[-0.180769,-0.0819578,0] isSelected:on
modPanel.addModToSelection (Edit_Poly ()) ui:on
actionMan.executeAction 1250838234 "40006"
subobjectLevel = 4
$.modifiers[#Edit_Poly].SetSelection #Face #{}
$.modifiers[#Edit_Poly].Select #Face #{2..6}
$.modifiers[#Edit_Poly].Select #Face #{3..6} select:off
$.modifiers[#Edit_Poly].SetOperation #ExtrudeFace
$.modifiers[#Edit_Poly].extrudeFaceHeight = 0.31
$.modifiers[#Edit_Poly].Commit ()
$.modifiers[#Edit_Poly].SetOperation #ExtrudeFace
$.modifiers[#Edit_Poly].extrudeFaceHeight = 2.41592
$.modifiers[#Edit_Poly].CommitAndRepeat ()
$.modifiers[#Edit_Poly].extrudeFaceHeight = 3.56126
$.modifiers[#Edit_Poly].CommitAndRepeat ()
$.modifiers[#Edit_Poly].extrudeFaceHeight = 3.09177
$.modifiers[#Edit_Poly].CommitAndRepeat ()
$.modifiers[#Edit_Poly].extrudeFaceHeight = 1.72458
$.modifiers[#Edit_Poly].CommitAndRepeat ()
$.modifiers[#Edit_Poly].extrudeFaceHeight = 1.36917
$.modifiers[#Edit_Poly].CommitAndRepeat ()
$.modifiers[#Edit_Poly].extrudeFaceHeight = 0.782

$.modifiers[#Edit_Poly].ConvertSelection #Face #Vertex
subobjectLevel = 1
$.modifiers[#Edit_Poly].Select #Vertex #{29..32} select:off
actionMan.executeAction 0 "40015"  -- Edit: Undo Scene Operation
subobjectLevel = 4
--macros.run "Tools" "SmartScale"$.modifiers[#Edit_Poly].SetOperation #Transform
$.modifiers[#Edit_Poly].ScaleSelection  [0.139344,1,1] axis:(matrix3 [0,-1,0] [0,0,1] [-1,0,0] [-30.2687,-0.0819578,36.7881])
$.modifiers[#Edit_Poly].Commit ()
actionMan.executeAction 1250838234 "40003"  -- Edit Poly: Vertex Level
subobjectLevel = 1
$.modifiers[#Edit_Poly].SetSelection #Vertex #{}
$.modifiers[#Edit_Poly].Select #Vertex #{31..32}
$.modifiers[#Edit_Poly].Select #Vertex #{29..30}
$.modifiers[#Edit_Poly].SetOperation #Transform
$.modifiers[#Edit_Poly].ScaleSelection  [0.315741,1,1] axis:(matrix3 [0,-1,0] [0,0,1] [-1,0,0] [-0.180769,-0.0819578,37.4727])
$.modifiers[#Edit_Poly].Commit ()
$.modifiers[#Edit_Poly].SetSelection #Vertex #{}
$.modifiers[#Edit_Poly].Select #Vertex #{27..28}
$.modifiers[#Edit_Poly].Select #Vertex #{25..26}
$.modifiers[#Edit_Poly].SetOperation #Transform
$.modifiers[#Edit_Poly].ScaleSelection  [0.531809,1,1] axis:(matrix3 [0,-1,0] [0,0,1] [-1,0,0] [-0.180769,-0.0819578,36.1035])
$.modifiers[#Edit_Poly].Commit ()
$.modifiers[#Edit_Poly].SetSelection #Vertex #{}
$.modifiers[#Edit_Poly].Select #Vertex #{21..22}
$.modifiers[#Edit_Poly].Select #Vertex #{23..24}
$.modifiers[#Edit_Poly].SetOperation #Transform
$.modifiers[#Edit_Poly].ScaleSelection  [0.718,1,1] axis:(matrix3 [0,-1,0] [0,0,1] [-1,0,0] [-0.180769,-0.0819578,34.3789])
$.modifiers[#Edit_Poly].Commit ()
$.modifiers[#Edit_Poly].SetSelection #Vertex #{}
$.modifiers[#Edit_Poly].Select #Vertex #{19..20}
$.modifiers[#Edit_Poly].Select #Vertex #{17..18}
$.modifiers[#Edit_Poly].SetOperation #Transform
$.modifiers[#Edit_Poly].ScaleSelection  [0.902272,1,1] axis:(matrix3 [0,-1,0] [0,0,1] [-1,0,0] [-0.180769,-0.0819578,31.2872])
$.modifiers[#Edit_Poly].Commit ()
actionMan.executeAction 1250838234 "40006"  -- Edit Poly: Polygon Level
subobjectLevel = 4
$.modifiers[#Edit_Poly].SetSelection #Face #{}
$.modifiers[#Edit_Poly].Select #Face #{3..14}
$.modifiers[#Edit_Poly].Select #Face #{11..14} select:off
$.modifiers[#Edit_Poly].Select #Face #{3..6} select:off
$.modifiers[#Edit_Poly].SetOperation #ExtrudeFace
$.modifiers[#Edit_Poly].extrudeFaceHeight = -1
$.modifiers[#Edit_Poly].extrudeFaceType = 1
$.modifiers[#Edit_Poly].Commit ()
actionMan.executeAction 1250838234 "40004"  -- Edit Poly: Edge Level
subobjectLevel = 2
$.modifiers[#Edit_Poly].SetSelection #Edge #{}
$.modifiers[#Edit_Poly].Select #Edge #{9..12}
$.modifiers[#Edit_Poly].SetOperation #ConnectEdges
$.modifiers[#Edit_Poly].connectEdgeSegments = 2
$.modifiers[#Edit_Poly].connectEdgePinch = 33
$.modifiers[#Edit_Poly].Commit ()
$.modifiers[#Edit_Poly].SetOperation #ChamferEdge
$.modifiers[#Edit_Poly].Commit ()
actionMan.executeAction 1250838234 "40004"  -- Edit Poly: Edge Level
subobjectLevel = 0
select $Box001
actionMan.executeAction 1250838234 "40004"  -- Edit Poly: Edge Level
subobjectLevel = 2
$.modifiers[#Edit_Poly].SetSelection #Edge #{}
$.modifiers[#Edit_Poly].Select #Edge #{94, 98, 110, 114}
$.modifiers[#Edit_Poly].ButtonOp #SelectEdgeRing
$.modifiers[#Edit_Poly].SetOperation #ConnectEdges
$.modifiers[#Edit_Poly].connectEdgePinch = 24
$.modifiers[#Edit_Poly].Commit ()
$.modifiers[#Edit_Poly].SetOperation #ChamferEdge
$.modifiers[#Edit_Poly].Commit ()
subobjectLevel = 4
$.modifiers[#Edit_Poly].SetSelection #Face #{}
$.modifiers[#Edit_Poly].Select #Face #{120, 122..123, 126, 128..129, 132..133, 136..137, 140..141, 144..145, 148..149, 152..153, 156..157, 159, 162..163, 166, 168..169, 171, 174, 176..177}
$.modifiers[#Edit_Poly].Select #Face #{119, 121, 124..125, 127, 130..131, 134..135, 138..139, 142..143, 146..147, 150..151, 154..155, 158, 160..161, 164..165, 167, 170, 172..173, 175, 178}
$.modifiers[#Edit_Poly].Select #Face #{119..120, 127..130, 155..162} select:off
$.modifiers[#Edit_Poly].Select #Face #{52, 54, 56, 58, 113..114, 117..118}
$.modifiers[#Edit_Poly].Select #Face #{51, 53, 55, 57, 111..112, 115..116}
$.modifiers[#Edit_Poly].SetOperation #ExtrudeFace
$.modifiers[#Edit_Poly].extrudeFaceHeight = 0.5
$.modifiers[#Edit_Poly].Commit ()
subobjectLevel = 0
subobjectLevel = 0
modPanel.setCurrentObject $.modifiers[#Edit_Poly]
$.name = "chest"
subobjectLevel = 4
$.modifiers[#Edit_Poly].ButtonOp #GrowSelection
$.modifiers[#Edit_Poly].ButtonOp #DetachFace
$.name = "chest_metal_part"
$.modifiers[#Edit_Poly].DetachToObject "chest_metal_part"
Box lengthsegs:1 widthsegs:1 heightsegs:1 length:0.761716 width:2.98197 height:1.32229 mapcoords:on transform:(matrix3 [1,0,0] [0,0,1] [0,-1,0] [1.04282,-17.3558,24.4848]) isSelected:on
$.name = "lock"
maxOps.cloneNodes $ cloneType:#copy newNodes:&nnl
select nnl
move $ [0,0,1.59866]
Torus smooth:2 segs:24 sides:12 radius1:1.74175 radius2:0.262188 mapcoords:on transform:(matrix3 [-1.62921e-007,-1,0] [0,0,1] [-1,1.62921e-007,0] [-0.448168,-18.4065,25.7553]) isSelected:on
actionMan.executeAction 0 "50001"
move $ [0.981063,-0.732899,0]
move $ [0.0334754,-0.124331,0]
$.name = "lock_ring"
$.radius1 = 2.02043
$.radius2 = 0.352188
move $ [0.21199,0,0]
move $ [0.140301,0.215179,0]
$.slice = on
$.sliceFrom = 180
move $ [0.122268,0,0]
actionMan.executeAction 0 "310"  -- Tools: Zoom Extents Selected
move $ [1.57037,0,0]
actionMan.executeAction 0 "310"  -- Tools: Zoom Extents Selected

clearSelection()
Box lengthsegs:1 widthsegs:1 heightsegs:1 length:5.28609 width:3.80677 height:1.81463 mapcoords:on transform:(matrix3 [0,-1,0] [0,0,1] [-1,0,0] [-9.15565e-007,-20.9457,25.7268]) isSelected:on
$.name = "Lock_Body"
actionMan.executeAction 0 "50001"
toolMode.coordsys #world
move $ [3.44153,0,0]
$.parent = $lock_ring
select $lock_ring
actionMan.executeAction 0 "50001"  -- Tools: Select and Move
move $ [-1.59895,0,0]
move $ [0,-0.531802,-0.492537]
macros.run "Tools" "SmartScale"
scale $ [0.945135,0.945135,0.945135]
actionMan.executeAction 0 "50001"  -- Tools: Select and Move
toolMode.coordsys #world
actionMan.executeAction 0 "50002"
toolMode.coordsys #view
rotate $ (angleaxis -32.1327 [0,0,1])
rotate $ (angleaxis -8.25049 [0,0,1])
actionMan.executeAction 0 "50001"  -- Tools: Select and Move
toolMode.coordsys #world
move $ [-0.108082,-0.0446568,0]


select $chest_metal_part
$.name = "chest"
select $Object
$.name = "chest_metal_part"
clearSelection()
select #($chest_metal_part, $chest, $lock, $lock001, $lock_ring, $Lock_Body)
deselect $chest
$.parent = $chest
select $chest

    '''

    MaxPlus.Core.EvalMAXScript(recorded_macro)
    chest = MaxPlus.INode.GetINodeByName('chest')
    set_scale_keys(target=chest, keyframes=[[0.001, 27], [0.1, 31]])
    set_position_keys(target=chest, keyframes=[[[-3.892, 0.349, -1.533], 27, [1, 1]],
                                               [[-3.892, 0.349, 0], 31, [1, 1]],
                                               [[-3.892, 0.349, -1.533], 33, [1, 1]]])
    chest.Rotate(MaxPlus.Quat().SetEuler(-0.1256, -0.0296556, 0.673356))
    chest.Position = MaxPlus.Point3(-3.941, 0.061, -1.533)
    land = MaxPlus.INode.GetINodeByName('land')
    chest.Parent = land


def create_and_animate_trees():
    """
    Function uses the create_palm() support function to create and animate some palm trees.
    It was created to show how to create basic geometry objects, use instances and use modificators.
    """

    palm = create_palm(diameter=1.3, segs_num=20, leafs_num=9, bending=34, id_num=1, anim_start=11, anim_end=16)
    palm.Rotate(MaxPlus.Quat().SetEuler(-0.051025, 0.366333, 1.69211))  # Rotate the palm
    palm.Position = MaxPlus.Point3(-8.5, -18.1, -2.5)  # Position the palm

    palm = create_palm(diameter=1.6, segs_num=20, leafs_num=9, bending=40, id_num=2, anim_start=23, anim_end=28)
    palm.Rotate(MaxPlus.Quat().SetEuler(0.0226778, 0.247746, 1.71606))
    palm.Position = MaxPlus.Point3(28, -6.3, -2.5)

    palm = create_palm(diameter=1.1, segs_num=18, leafs_num=9, bending=24, id_num=3, anim_start=15, anim_end=20)
    palm.Rotate(MaxPlus.Quat().SetEuler(0.0226778, 0.247746, -1.94985))
    palm.Position = MaxPlus.Point3(34, -34, -2.5)

    palm = create_palm(diameter=1.1, segs_num=24, leafs_num=9, bending=24, id_num=4, anim_start=20, anim_end=25)
    palm.Rotate(MaxPlus.Quat().SetEuler(0.0226778, 0.244222, -1.03672))
    palm.Position = MaxPlus.Point3(14, -19, -2.5)


def change_hierarchy_and_animate():
    """
    Function modifies the hierarchy of scen and creates some final animations, that ware not possible to create earlier.
    It also creates cameras and lights.
    """
    camera = MaxPlus.Factory.CreateFreeCamera()
    camera.SetFOV(1.14267)
    camera_node = MaxPlus.Factory.CreateNode(camera)
    camera_node.Rotate(MaxPlus.Quat().SetEuler(1.1775, 0.0, -1.57))
    camera_node.Position = MaxPlus.Point3(-149.0, 3.569, 52.082)
    try:
        viewport = MaxPlus.ViewportManager.GetViewportByID(3)
        viewport.SetViewCamera(camera_node)
    except:
        print "Script was not ab;e tp set view from the camera"
        pass

    light_id = MaxPlus.Class_ID(0x7bf61478, 0x522e4705)
    skylight = MaxPlus.Factory.CreateLight(light_id)
    skylight.ParameterBlock.multiplier.Value = 0.08
    skylight.ParameterBlock.rgb.Value = MaxPlus.Color(247 / 255.0, 249 / 255.0, 1)
    MaxPlus.Factory.CreateNode(skylight)

    light_id = MaxPlus.Class_ID(1540123970, 206521102)
    light = MaxPlus.Factory.CreateLight(light_id)
    light.ParameterBlock.intensity.Value = 80000
    light.ParameterBlock.light_radius.Value = 25
    light.ParameterBlock.castShadows.Value = True
    light.SetShadowType(1)
    light_node = MaxPlus.Factory.CreateNode(light)
    light_node.Rotate(MaxPlus.Quat().SetEuler(0.785398, 0, -0.959931))
    light_node.Position = MaxPlus.Point3(-186.942, -134.755, 189.936)

    # All the geometry that has no parent node will be linked to the new helper node. It will rotate a little bit.
    helper_classid = MaxPlus.Class_ID(8872500, 0)  # Class ID obtained from max with maxscript command: 'obj.classid'
    new_helper = MaxPlus.Factory.CreateHelperObject(helper_classid)
    new_helper_node = MaxPlus.Factory.CreateNode(new_helper)

    # Rotate helper:
    MaxPlus.Animation.SetAnimateButtonState(True)
    # MaxPlus.Animation.SetDefaultTangentType(4, 4)
    rotation = MaxPlus.Quat().SetEuler(0, 0.0, 0.01 * math.pi)  # Rotation = 45 deg.
    new_helper_node.Rotate(rotation, 260 * TICKS)
    MaxPlus.Animation.SetDefaultTangentType(3, 3)
    rotation = MaxPlus.Quat().SetEuler(0, 0.0, -0.1 * math.pi)
    new_helper_node.Rotate(rotation, 1)  # Rotate from frames 0 to 260
    MaxPlus.Animation.SetAnimateButtonState(False)

    # Make the helper a parent of geometry
    objects_list = []
    for name in ['land', 'water', 'cloud', 'shark']:
        node = MaxPlus.INode.GetINodeByName(name)
        objects_list.append(node)
    for obj in objects_list:
        obj.Parent = new_helper_node


def create_and_assign_materials():
    """
    Function creates and applies materials to the objects
    It was created to show how to use the Material Manager.
    """
    # Simple, gray material for cloud and shark:
    mat_id = MaxPlus.Class_ID(1890604853, 1242969684)  # Class_ID of Arch & Design material
    m = MaxPlus.Factory.CreateMaterial(mat_id)
    m.Diffuse = MaxPlus.Color(0.84, 0.84, 0.84)  # Set parameters of the material
    m.ParameterBlock.refl_weight.Value = 0
    m.ParameterBlock.diff_rough.Value = 1
    m.SetName(MaxPlus.WStr('Gray_material'))

    # Assign material to the shark, cloud and metal parts of the chest. Find them by name.
    for name in ['cloud', 'shark', "lock", "lock001", "lock_ring", "chest_metal_part", "Lock_Body"]:
        node = MaxPlus.INode.GetINodeByName(name)
        node.Material = m
    pass

    # Water material, more material parameters included:
    m = MaxPlus.Factory.CreateMaterial(mat_id)
    m.ParameterBlock.diff_color.Value = MaxPlus.Color(0, 0.208633, 0.201736)
    m.ParameterBlock.diff_rough.Value = 0.0
    m.ParameterBlock.diff_weight.Value = 1.0
    m.ParameterBlock.refl_color.Value = MaxPlus.Color(1, 1, 1)
    m.ParameterBlock.refl_gloss.Value = 0.840000092983
    m.ParameterBlock.refl_samples.Value = 8
    m.ParameterBlock.refl_interp.Value = False
    m.ParameterBlock.refl_hlonly.Value = False
    m.ParameterBlock.refl_metal.Value = False
    m.ParameterBlock.refl_weight.Value = 0.600000023842
    m.ParameterBlock.refr_color.Value = MaxPlus.Color(0.435294, .435294, 0.435294)
    m.ParameterBlock.refr_gloss.Value = 0.760000050068
    m.ParameterBlock.refr_samples.Value = 8
    m.ParameterBlock.refr_interp.Value = False
    m.ParameterBlock.refr_ior.Value = 1.30000007153
    m.ParameterBlock.refr_weight.Value = 0.429999947548
    m.ParameterBlock.refr_trans_on.Value = False
    m.ParameterBlock.refr_transc.Value = MaxPlus.Color(1, 1, 1)
    m.ParameterBlock.refr_transw.Value = 0.0
    m.ParameterBlock.anisotropy.Value = 1.0
    m.ParameterBlock.anisoangle.Value = 0.0
    m.ParameterBlock.aniso_mode.Value = 0
    m.ParameterBlock.aniso_channel.Value = 0
    m.ParameterBlock.refl_func_fresnel.Value = True
    m.ParameterBlock.refl_func_low.Value = 0.20000000298
    m.ParameterBlock.refl_func_high.Value = 1.0
    m.ParameterBlock.refl_func_curve.Value = 5.0
    m.ParameterBlock.refl_falloff_on.Value = True
    m.ParameterBlock.refl_falloff_dist.Value = 19.4505996704
    m.ParameterBlock.refl_falloff_color_on.Value = True
    m.ParameterBlock.refl_falloff_color.Value = MaxPlus.Color(0.2, 0.2, 0.2)
    m.ParameterBlock.opts_refl_depth.Value = 4
    m.ParameterBlock.refl_cutoff.Value = 0.00999999977648
    m.ParameterBlock.refr_falloff_on.Value = True
    m.ParameterBlock.refr_falloff_dist.Value = 1.65000009537
    m.ParameterBlock.refr_falloff_color_on.Value = True
    m.ParameterBlock.refr_falloff_color.Value = MaxPlus.Color(0.12549, 0.988235, 1)
    m.ParameterBlock.opts_refr_depth.Value = 6
    m.ParameterBlock.refr_cutoff.Value = 0.00999999977648
    m.ParameterBlock.opts_indirect_multiplier.Value = 1.0
    m.ParameterBlock.opts_fg_quality.Value = 1.0
    m.ParameterBlock.inter_density.Value = 2
    m.ParameterBlock.intr_refl_samples.Value = 2
    m.ParameterBlock.intr_refl_ddist_on.Value = False
    m.ParameterBlock.intr_refl_ddist.Value = 0.0
    m.ParameterBlock.intr_refr_samples.Value = 2
    m.ParameterBlock.single_env_sample.Value = False
    m.ParameterBlock.opts_round_corners_on.Value = False
    m.ParameterBlock.opts_round_corners_radius.Value = 10.0
    m.ParameterBlock.opts_round_corners_any_mtl.Value = True
    m.ParameterBlock.opts_ao_on.Value = False
    m.ParameterBlock.opts_ao_exact.Value = False
    m.ParameterBlock.opts_ao_use_global_ambient.Value = False
    m.ParameterBlock.opts_ao_samples.Value = 16
    m.ParameterBlock.opts_ao_distance.Value = 4.0
    m.ParameterBlock.opts_ao_dark.Value = MaxPlus.Color(0.2, 0.2, 0.2)
    m.ParameterBlock.opts_ao_ambient.Value = MaxPlus.Color(0, 0, 0)
    m.ParameterBlock.opts_ao_do_details.Value = True
    m.ParameterBlock.opts_no_area_hl.Value = True
    m.ParameterBlock.opts_1sided.Value = False
    m.ParameterBlock.opts_do_refractive_caustics.Value = False
    m.ParameterBlock.opts_skip_inside.Value = True
    m.ParameterBlock.opts_hl_to_refl_balance.Value = 1.0
    m.ParameterBlock.opts_backface_cull.Value = False
    m.ParameterBlock.opts_propagate_alpha.Value = False
    m.ParameterBlock.diff_color_map_on.Value = True
    m.ParameterBlock.diff_rough_map_on.Value = True
    m.ParameterBlock.refl_color_map_on.Value = True
    m.ParameterBlock.refl_gloss_map_on.Value = True
    m.ParameterBlock.refr_color_map_on.Value = False
    m.ParameterBlock.refr_gloss_map_on.Value = True
    m.ParameterBlock.refr_ior_map_on.Value = True
    m.ParameterBlock.refr_transc_map_on.Value = True
    m.ParameterBlock.refr_transw_map_on.Value = True
    m.ParameterBlock.anisotropy_map_on.Value = True
    m.ParameterBlock.anisoangle_map_on.Value = True
    m.ParameterBlock.refl_falloff_color_map_on.Value = True
    m.ParameterBlock.refr_falloff_color_map_on.Value = True
    m.ParameterBlock.indirect_multiplier_map_on.Value = True
    m.ParameterBlock.fg_quality_map_on.Value = True
    m.ParameterBlock.ao_dark_map_on.Value = True
    m.ParameterBlock.ao_ambient_map_on.Value = True
    m.ParameterBlock.bump_map_on.Value = False
    m.ParameterBlock.displacement_map_on.Value = True
    m.ParameterBlock.cutout_map_on.Value = True
    m.ParameterBlock.environment_map_on.Value = False
    m.ParameterBlock.add_color_map_on.Value = True
    m.ParameterBlock.radius_map_on.Value = True
    m.SetName(MaxPlus.WStr('Water_material'))

    node = MaxPlus.INode.GetINodeByName('water')
    node.Material = m

    # Sand:
    m = MaxPlus.Factory.CreateMaterial(mat_id)
    m.Diffuse = MaxPlus.Color(1, 0.74, 0.45)
    m.ParameterBlock.refl_weight.Value = 0
    m.ParameterBlock.diff_rough.Value = 0
    m.SetName(MaxPlus.WStr('Sand_material'))

    node = MaxPlus.INode.GetINodeByName('land')
    node.Material = m

    # Wood:
    m = MaxPlus.Factory.CreateMaterial(mat_id)
    m.Diffuse = MaxPlus.Color(0.18, 0.13, 0.13)
    m.ParameterBlock.refl_weight.Value = 0
    m.ParameterBlock.diff_rough.Value = 0
    m.SetName(MaxPlus.WStr('Wood_material'))

    node = MaxPlus.INode.GetINodeByName('chest')
    node.Material = m
    # Assign material 'Wood_material' to nodes with prefix 'Palm' in name
    append_material_by_prefix(prefix='Palm', material=m)

    # Leafs:
    m = MaxPlus.Factory.CreateMaterial(mat_id)
    m.Diffuse = MaxPlus.Color(0.4, 1, 0.3)
    m.ParameterBlock.refl_weight.Value = 0
    m.ParameterBlock.diff_rough.Value = 0
    m.SetName(MaxPlus.WStr('Leaf_material'))

    append_material_by_prefix(prefix='leaf', material=m)


#
#
# Gui and interface:
#
#


class DataTable:
    """
    Object stores the parameters of currently running instance of script. It also runs the functions
    and makes callbacks to UI elements easier.
    """

    target_list = None
    target_label = None
    scores_list = []
    next_step = 0  # the step that should be performed next (when running the script step-by-step)
    ignore_steps = False  # if ignore_steps is false the animation is step by step

    def __init__(self):
        pass

    def run(self, text, function, path=None):
        """
        Run the script: create the scene. It can run step-by-step and stop after every part or run every function
        one after another. The function also measures an execution time of commands and updates the UI elements.

        :param text: string - Name of the current step that will be displayed in the UI and scores table.
        :param function: function() - Function that will be run.
        :param path: string - Additional parameter: path that can be passed to the function as parameter:
                              required by some functions.
        """

        self.target_label.setText(text)  # Update the label of UI
        if path is None:  # If no path was passed as argument, then do not pass this variable to target function
            ts = time.time()  # Start measuring time
            function()  # Execute the function passed as an argument
        else:
            ts = time.time()
            function(path)  # if path was passed then pass it to the target function
        te = time.time()  # Record the ending time of command
        score = [text, te - ts]  # Measure the interval
        self.scores_list.append(score)  # append the

        try:
            self.target_list.addItem(QListWidgetItem(str(score)))  # Add measured time to scores list in UI
        except:
            pass

    def save(self):
        """
        Funcrtion saves the execution times of commands to the file.
        """

        i = 0
        scores = []

        while i < self.target_list.count():
            scores.append(self.target_list.item(i).text())
            i += 1

        path = QFileDialog.getExistingDirectory(None, 'Select folder to save scores_3DSMax.txt')
        with open(path + '/scores_3DSMax.txt', 'w') as file_:
            for score in scores:
                file_.write(score + '\n')

    def reset(self):
        """
        Function resets the max file and parameters of this object to the initial state.
        """

        MaxPlus.FileManager.Reset(True)
        MaxPlus.ViewportManager.ForceCompleteRedraw()  # This and the next functions should be run after running the
        MaxPlus.ViewportManager.EnableSceneRedraw()  # script or the viewports will not update.
        pass


class GUI(QWidget):
    """
    GUI object. Standard way of using PySide.
    PySide is recommended in documentation of 3Ds Max Python API
    """

    path = "C:/"

    def __init__(self):
        """
        Setting the content of the GUI
        """

        super(GUI, self).__init__()

        self.resize(250, 150)  # Set the size of window
        self.center()

        self.setWindowTitle('Skrypt - 3Ds Max')  # Set the title of window

        grid = QGridLayout()  # Create a grid layout
        grid_internal = QGridLayout()
        self.label_info = QLabel('Launch the script with `start` button')  # Create a label GUI element
        btn_step = QPushButton('Step by step')  # Create a button
        btn_start = QPushButton('Run all steps')
        self.connect(btn_start, SIGNAL("clicked()"), self.fn_no_steps)  # Connect button to function
        self.connect(btn_step, SIGNAL("clicked()"), self.fn_step)
        self.times_list = QListWidget(self)  # Create a list widget
        btn_save = QPushButton('Save scores')
        btn_reset = QPushButton('Clear the scene')

        grid.addWidget(self.label_info, 0, 0)  # Add the widget to the layout

        grid_internal.addWidget(btn_step, 0, 0)
        grid_internal.addWidget(btn_start, 0, 1)

        grid.addLayout(grid_internal, 1, 0)
        grid.addWidget(self.times_list, 2, 0)
        grid.addWidget(btn_save, 3, 0)
        grid.addWidget(btn_reset, 4, 0)

        self.data_table = DataTable()
        self.data_table.target_list = self.times_list
        self.data_table.target_label = self.label_info

        self.connect(btn_reset, SIGNAL("clicked()"), self.data_table.reset)
        self.connect(btn_save, SIGNAL("clicked()"), self.data_table.save)

        self.setLayout(grid)  # Set the layout of the window
        self.show()

    def center(self):
        """
        Function places window on the center of the screen. It is not neccesary for script to run.
        """

        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

    def fn_step(self):
        """
        Run function step-by-step: make one step.
        """

        self.data_table.ignore_steps = False
        self.fn_start()

    def fn_no_steps(self):
        """
        Run function: make all the steps.
        """

        self.data_table.ignore_steps = True
        self.fn_start()

    def fn_start(self):
        """
        Function runs other functions in a right order and with right parameters.
        """

        MaxPlus.ViewportManager.DisableSceneRedraw()  # Makes the script run faster: Viewports will not be updated.

        while not os.path.isfile(self.path + '/land.obj'):  # checks if the folder includes necessary file.
            # If not, then shows the QFileDialog that makes it possible to select the right one.

            self.path = QFileDialog.getExistingDirectory(self,
                                                               'Select the folder of additional files (named "common")')
            print self.path

        self.label_info.setText("Script started")

        functions_with_names = [["Setup the scene", prepare_scene, self.path],
                                ["Import basic objects", import_and_animate_basic_meshes, self.path],
                                ["Create a shark finn and a cloud", create_shark_and_cloud, None],
                                ["Create a chest with Macro script", create_chest, None],
                                ["Create and animate trees", create_and_animate_trees, None],
                                ["Fix objects hierarchy, finish the animation", change_hierarchy_and_animate, None],
                                ["Create and assign materials", create_and_assign_materials, None]]

        if self.data_table.ignore_steps:
            for action_num in xrange(self.data_table.next_step, len(functions_with_names)):
                line = functions_with_names[action_num]
                self.data_table.run(text=line[0], function=line[1], path=line[2])
        else:
            action_num = self.data_table.next_step
            self.data_table.next_step += 1
            line = functions_with_names[action_num]
            self.data_table.run(text=line[0], function=line[1], path=line[2])

        MaxPlus.ViewportManager.ForceCompleteRedraw()
        MaxPlus.ViewportManager.EnableSceneRedraw()
        pass


def main():
    app = QApplication.instance()  # As suggested in 3Ds Max Python API documentation
    if not app:
        app = QApplication([])
    gui = GUI()
    try:
        import sys
        print 'goodbye world'
        sys.exit(
            app.exec_())  # As suggested in 3Ds Max Python API documentation
    # Safe way to leave program at any point and allow objects and resources to be cleaned up.
    # Prevent 3ds Max from reporting a system exit as an error in the listener.
    except SystemExit:
        pass


if __name__ == '__main__':
    main()
